﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ZCustomControl.Helpers;
using ZCustomControl.Models;

namespace ZCustomControl.Controls
{
    public class ZTreeView : TreeView
    {
        #region Consts
        #endregion

        #region Fields

        //记录右键按下时点击测试的命中对象
        private TreeViewItem _rightButtonDownHitItem = null;
        //指示鼠标左键是否按下
        private bool _isMouseLeftButtonDown = false;
        //拖动中的条目
        private TreeViewItem _draggingItem = null;
        //只是控件是否已经初始化模板
        private bool _hasTemplateApplied = false;
        //指示选中节点的时候是否展开其子节点
        private bool _isExpandedWhenSelected = false;

        #endregion

        #region Properties

        public Action<ViewItemModel> OnRightButtonClick = null;
        public Action<ViewItemModel> OnDoubleClickTreeItem = null;

        public bool IsExpandedWhenSelected
        {
            get { return _isExpandedWhenSelected; }
            set { _isExpandedWhenSelected = value; }
        }

        #endregion

        #region Dependency Property

        // 无数据图标高度
        public static readonly DependencyProperty NoDataIconHeightProperty
            = DependencyProperty.Register("NoDataIconHeight", typeof(double), typeof(ZTreeView), new PropertyMetadata(64.0, null));

        //无数据图标宽度
        public static readonly DependencyProperty NoDataIconWidthProperty
            = DependencyProperty.Register("NoDataIconWidth", typeof(double), typeof(ZTreeView), new PropertyMetadata(64.0, null));

        //无数据时显示的图标
        public static readonly DependencyProperty NoDataIconProperty
            = DependencyProperty.Register("NoDataIcon", typeof(ImageSource), typeof(ZTreeView), new PropertyMetadata(null, null));

        //双击命令
        public static readonly DependencyProperty DoubleClickCommandProperty
            = DependencyProperty.Register("DoubleClickCommand", typeof(ICommand), typeof(ZTreeView), new PropertyMetadata(null, null));

        //右键命名
        public static readonly DependencyProperty RightClickCommandProperty
            = DependencyProperty.Register("RightClickCommand", typeof(ICommand), typeof(ZTreeView), new PropertyMetadata(null, null));

        //无数据提示文字信息
        public static readonly DependencyProperty NoDataTipsTextProperty
            = DependencyProperty.Register("NoDataTipsText", typeof(string), typeof(ZTreeView), new PropertyMetadata("无数据", null));

        //无数据提示文字信息前景色
        public static readonly DependencyProperty NoDataTipsTextForegroundProperty
            = DependencyProperty.Register("NoDataTipsTextForeground", typeof(Brush), typeof(ZTreeView), new PropertyMetadata(new SolidColorBrush(Colors.Gray), null));

        //无数据提示图片源
        public static readonly DependencyProperty NoDataIconSourceProperty
            = DependencyProperty.Register("NoDataIconSource", typeof(ImageSource), typeof(ZTreeView), new PropertyMetadata(null, null));

        //是否允许拖动树条目
        public static readonly DependencyProperty IsDragEnableProperty
            = DependencyProperty.Register("IsDragEnable", typeof(bool), typeof(ZTreeView), new PropertyMetadata(true, null));

        //选中的树节点
        public static readonly DependencyProperty SelectedViewItemProperty
            = DependencyProperty.Register("SelectedViewItem", typeof(ViewItemModel), typeof(ZTreeView), new PropertyMetadata(null, OnSelectedViewItemChanged));

        #endregion

        #region Property Wrappers

        public double NoDataIconHeight
        {
            get { return (double)GetValue(NoDataIconHeightProperty); }
            set { SetValue(NoDataIconHeightProperty, value); }
        }

        public double NoDataIconWidth
        {
            get { return (double)GetValue(NoDataIconWidthProperty); }
            set { SetValue(NoDataIconWidthProperty, value); }
        }

        public ImageSource NoDataIcon
        {
            get { return (ImageSource)GetValue(NoDataIconProperty); }
            set { SetValue(NoDataIconProperty, value); }
        }

        public ICommand DoubleClickCommand
        {
            get { return (ICommand)GetValue(DoubleClickCommandProperty); }
            set { SetValue(DoubleClickCommandProperty, value); }
        }

        public ICommand RightClickCommand
        {
            get { return (ICommand)GetValue(RightClickCommandProperty); }
            set { SetValue(RightClickCommandProperty, value); }
        }

        public string NoDataTipsText
        {
            get { return (string)GetValue(NoDataTipsTextProperty); }
            set { SetValue(NoDataTipsTextProperty, value); }
        }

        public Brush NoDataTipsTextForeground
        {
            get { return (Brush)GetValue(NoDataTipsTextForegroundProperty); }
            set { SetValue(NoDataTipsTextForegroundProperty, value); }
        }

        public ImageSource NoDataIconSource
        {
            get { return (ImageSource)GetValue(NoDataIconSourceProperty); }
            set { SetValue(NoDataIconSourceProperty, value); }
        }

        public bool IsDragEnable
        {
            get { return (bool)GetValue(IsDragEnableProperty); }
            set { SetValue(IsDragEnableProperty, value); }
        }

        public ViewItemModel SelectedViewItem
        {
            get { return (ViewItemModel)GetValue(SelectedViewItemProperty); }
            set
            {
                SetValue(SelectedViewItemProperty, value);
            }
        }

        #endregion

        #region Routed Events

        public static readonly RoutedEvent SelectedViewItemChangedEvent
            = EventManager.RegisterRoutedEvent("SelectedViewItemChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ZTreeView));

        #endregion

        #region Constructors

        static ZTreeView()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ZTreeView), new FrameworkPropertyMetadata(typeof(ZTreeView)));
        }

        #endregion

        #region Override Methods

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            if (NoDataIcon == null)
            {
                NoDataIcon = new BitmapImage(new Uri(@"pack://application:,,,/ZCustomControl;component/Images/NoDataGray.png", UriKind.Absolute));
            }
            _hasTemplateApplied = true;

            this.PreviewMouseRightButtonDown += ZTreeView_PreviewMouseRightButtonDown;
            this.PreviewMouseRightButtonUp += ZTreeView_PreviewMouseRightButtonUp;
            this.PreviewMouseLeftButtonDown += ZTreeView_PreviewMouseLeftButtonDown;
            this.PreviewMouseLeftButtonUp += ZTreeView_PreviewMouseLeftButtonUp;
            this.MouseMove += ZTreeView_MouseMove;
            this.PreviewMouseDoubleClick += ZTreeView_PreviewMouseDoubleClick;
        }

        #endregion

        #region Property Changed Callbacks

        private static void OnSelectedViewItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ZTreeView zTree = d as ZTreeView;
            if (zTree == null)
            {
                return;
            }

            ViewItemModel newVim = e.NewValue as ViewItemModel;
            if (newVim == null || e.NewValue == e.OldValue)
            {
                return;
            }

            //设置树的选中项
            List<ViewItemModel> allViewItemModelList = new List<ViewItemModel>();
            foreach (ViewItemModel rootViewItem in zTree.ItemsSource)
            {
                allViewItemModelList.AddRange(ViewItemModelHelper.GetAllTreeNode(rootViewItem));
            }

            ViewItemModel vim = allViewItemModelList.Find(p => p.Id == newVim.Id);
            if (vim == null)
            {
                return;
            }

            zTree.BringItemIntoView(vim);
        }

        #endregion

        #region Event Methods

        private void ZTreeView_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            _rightButtonDownHitItem = null;
            Point pos = e.GetPosition(this);
            HitTestResult hitResult = VisualTreeHelper.HitTest(this, pos);
            if (hitResult == null)
            {
                return;
            }
            _rightButtonDownHitItem = LVTreeHelper.GetAncestor<TreeViewItem>(hitResult.VisualHit);
        }

        private void ZTreeView_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            Point pos = e.GetPosition(this);
            HitTestResult hitResult = VisualTreeHelper.HitTest(this, pos);
            if (hitResult == null)
            {
                return;
            }
            TreeViewItem dr = LVTreeHelper.GetAncestor<TreeViewItem>(hitResult.VisualHit);
            if (dr == null)
            {
                return;
            }

            ViewItemModel vim = dr.DataContext as ViewItemModel;
            if (vim == null)
            {
                return;
            }

            if (RightClickCommand != null)
            {
                RightClickCommand.Execute(vim);
            }

            if (OnRightButtonClick != null)
            {
                OnRightButtonClick(vim);
            }
        }

        private void ZTreeView_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            Point pos = e.GetPosition(this);
            HitTestResult hitResult = VisualTreeHelper.HitTest(this, pos);
            if (hitResult == null)
            {
                return;
            }

            Button btn = LVTreeHelper.GetAncestor<Button>(hitResult.VisualHit);
            if (btn != null)
            {
                return;
            }

            TreeViewItem dr = LVTreeHelper.GetAncestor<TreeViewItem>(hitResult.VisualHit);
            if (dr == null)
            {
                return;
            }

            ViewItemModel vim = dr.DataContext as ViewItemModel;
            if (vim == null)
            {
                return;
            }

            if (OnDoubleClickTreeItem != null)
            {
                OnDoubleClickTreeItem(vim);
            }

            if (DoubleClickCommand != null)
            {
                DoubleClickCommand.Execute(vim);
            }
        }

        private void ZTreeView_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _isMouseLeftButtonDown = true;
            _draggingItem = null;
            if (!IsHitUndragableControl(sender, e))
            {
                return;
            }

            TreeViewItem tvm = GetHitTreeViewItem(sender, e);
            _draggingItem = tvm;
        }

        private void ZTreeView_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            _isMouseLeftButtonDown = false;
        }

        private void ZTreeView_MouseMove(object sender, MouseEventArgs e)
        {
            if (!IsDragEnable)//不允许拖动
            {
                return;
            }

            if (!(_isMouseLeftButtonDown && e.LeftButton == MouseButtonState.Pressed))//鼠标未按下
            {
                return;
            }

            if (_draggingItem == null)//未选中条目
            {
                return;
            }

            ViewItemModel data = _draggingItem.DataContext as ViewItemModel;
            DragDrop.DoDragDrop(_draggingItem, data, DragDropEffects.Copy);
        }

        #endregion

        #region Private Methods

        private bool IsHitUndragableControl(object sender, MouseButtonEventArgs e)
        {
            TreeView treeView = sender as TreeView;
            if (treeView == null)
            {
                return false;
            }

            Point pos = e.GetPosition(treeView);
            HitTestResult hitResult = VisualTreeHelper.HitTest(treeView, pos);
            if (hitResult == null)
            {
                return false;
            }

            TextBox tb = LVTreeHelper.GetAncestor<TextBox>(hitResult.VisualHit);
            if (tb != null)
            {
                return false;
            }

            Button btn = LVTreeHelper.GetAncestor<Button>(hitResult.VisualHit);
            if (btn != null)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// 获取点击中的TreeViewItem
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        private TreeViewItem GetHitTreeViewItem(object sender, MouseButtonEventArgs e)
        {
            TreeView treeView = sender as TreeView;
            if (treeView == null)
            {
                return null;
            }

            Point pos = e.GetPosition(treeView);
            HitTestResult hitResult = VisualTreeHelper.HitTest(treeView, pos);
            if (hitResult == null)
            {
                return null;
            }
            TreeViewItem dr = LVTreeHelper.GetAncestor<TreeViewItem>(hitResult.VisualHit);
            return dr;
        }

        /// <summary>
        /// 展开指定节点
        /// </summary>
        /// <param name="viewItemModel"></param>
        /// <param name="treeView"></param>
        private void ExpandTreeNode(ViewItemModel viewItemModel, ItemsControl treeView)
        {
            if (viewItemModel == null || treeView == null)
            {
                return;
            }

            ItemsControl expandingItemsBase = treeView;

            Stack<ViewItemModel> treeNodeStack = new Stack<ViewItemModel>();
            treeNodeStack.Push(viewItemModel);
            while (viewItemModel.Parent != null)
            {
                viewItemModel = viewItemModel.Parent;
                treeNodeStack.Push(viewItemModel);
            }

            while (treeNodeStack.Count > 0)
            {
                ViewItemModel expandingViewItem = treeNodeStack.Pop();
                if (expandingItemsBase != null)
                {
                    bool isExpanded = treeNodeStack.Count > 0 ? true : false;
                    expandingItemsBase = BringIntoView(expandingViewItem, expandingItemsBase, isExpanded);
                }
            }

            if (expandingItemsBase != null && (expandingItemsBase is TreeViewItem))
            {
                (expandingItemsBase as TreeViewItem).IsSelected = true;
            }
        }

        /// <summary>
        /// 定位并显示指定节点
        /// </summary>
        /// <param name="treeNode"></param>
        /// <param name="itemsControl"></param>
        /// <returns></returns>
        private ItemsControl BringIntoView(ViewItemModel treeNode, ItemsControl itemsControl, bool isExpanded)
        {
            if (itemsControl == null)
            {
                return null;
            }

            itemsControl.ApplyTemplate();
            if (itemsControl.Template != null)
            {
                ItemsPresenter ip = (ItemsPresenter)itemsControl.Template.FindName("ItemHost", (FrameworkElement)itemsControl);
                if (ip != null)
                {
                    ip.ApplyTemplate();
                }
            }
            itemsControl.UpdateLayout();

            VirtualizingPanel virtualizingPanel = itemsControl.GetItemsHost() as VirtualizingPanel;
            if (virtualizingPanel != null)
            {
                virtualizingPanel.CallEnsureGenerator();
            }

            int selectedItemIndex = -1;
            int childItemCount = itemsControl.Items.Count;
            for (int i = 0; i < childItemCount; i++)
            {
                ViewItemModel tviItem = itemsControl.Items[i] as ViewItemModel;
                if (null != tviItem && tviItem == treeNode)
                {
                    selectedItemIndex = i;
                    break;
                }
            }

            if (selectedItemIndex < 0)
            {
                return null;
            }

            if (virtualizingPanel != null)
            {
                virtualizingPanel.CallBringIndexIntoView(selectedItemIndex);
            }
            TreeViewItem itemSelected = (TreeViewItem)itemsControl.ItemContainerGenerator.ContainerFromIndex(selectedItemIndex);

            if (null != itemSelected)
            {
                if (isExpanded)
                {
                    itemSelected.IsExpanded = true;
                }

                itemSelected.UpdateLayout();
                itemSelected.BringIntoView();
            }

            return itemSelected;
        }

        /// <summary>
        /// 显示给定的节点
        /// </summary>
        /// <param name="vim"></param>
        private void BringItemIntoView(ViewItemModel vim)
        {

            if (!_hasTemplateApplied)
            {
                ApplyTemplate();
                if (Template != null)
                {
                    ItemsPresenter ip = (ItemsPresenter)Template.FindName("ItemHost", (FrameworkElement)this);
                    if (ip != null)
                    {
                        ip.ApplyTemplate();
                    }
                }
                else
                {
                    UpdateLayout();
                }
            }
            ExpandTreeNode(vim, this);
        }

        #endregion

        #region Public Methods
        #endregion
    }
}
